#pragma once
#include<iostream>
#include<vector>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
template<typename T>
class circular_queue {
    public:
        circular_queue(int size = 500)
            :_ring(size)
            ,_max_size(size)
            ,_head(0)
            ,_tail(0)
        {
            int n = ::sem_init(&_data_sem, 0, 0);
            int m = ::sem_init(&_space_sem, 0, _max_size);
            pthread_mutex_init(&_p_lock, nullptr);
            pthread_mutex_init(&_c_lock, nullptr);
        }
        void push(const T& data)//生产者
        {
            ::sem_wait(&_space_sem);//预定空间
            pthread_mutex_lock(&_p_lock);//
            _ring[_tail] = data;//生产者生产数据
            _tail++;
            _tail %= _max_size;//维持环形
            pthread_mutex_unlock(&_p_lock);//
            ::sem_post(&_data_sem);
            
        }
        void pop(T *out)//消费者
        {
            ::sem_wait(&_data_sem);//预定数据
            pthread_mutex_lock(&_c_lock);//
            *out = _ring[_head];//消费者消费数据
            _head++;
            _head %= _max_size;//维持环形
            pthread_mutex_unlock(&_c_lock);//
            ::sem_post(&_space_sem);
        }
        ~circular_queue()
        {
            int n = ::sem_destroy(&_data_sem);
            int m = ::sem_destroy(&_space_sem);
            pthread_mutex_destroy(&_p_lock);
            pthread_mutex_destroy(&_c_lock);
        }
    private:
        std::vector<T> _ring;//环-》临界资源
        int _max_size;
        int _head;//指向队头->消费者
        int _tail;//指向队尾->生产者
        sem_t _data_sem;//数据信号量
        sem_t _space_sem;//空间信号量
        pthread_mutex_t _p_lock;//生产者的互斥锁
        pthread_mutex_t _c_lock;//消费者的互斥锁
};


class Sem{
    public:
    Sem(int value = 1):_init_value(value)
    {
        int n = ::sem_init(&_sem, 0, _init_value);
    }
    void wait()//P操作
    {
        int n = ::sem_wait(&_sem);
    }
    void post()//V操作
    {
        int n = ::sem_post(&_sem);
    }
    ~Sem()
    {
        int n = ::sem_destroy(&_sem);
    }
    private:
        sem_t _sem;
        int _init_value;
};